package com.es.util.reflection;

import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.util.*;

/**
 * 反射工具类
 *
 * @author 赵伟
 * @date 20210705
 * @description 提供了一系列的获取某一个类的信息的方法
 * 包括获取全类名，实现的接口，接口的泛型等
 * 并且提供了根据 Class类型获取对应的实例对象的方法，以及修改属性和调用对象的方法等
 */
public class ReflectionUtil {

    /**
     * 空字符串
     */
    private final static String STR_EMPTY = "";
    /**
     * 获取单例方法名称
     */
    private final static String FUNC_SINGLEINSTANCE = "getInstance";
    /**
     * 八大基本数据类型对应类型转换
     */
    private final static Map<Class<?>, Class<?>> MAP_BASICTRAANSIT = new HashMap<Class<?>, Class<?>>() {{
        put(Byte.class, byte.class);
        put(Short.class, short.class);
        put(Integer.class, int.class);
        put(Long.class, long.class);
        put(Character.class, char.class);
        put(Float.class, float.class);
        put(Double.class, double.class);
        put(Boolean.class, boolean.class);
    }};

    /************************************调试获取基本信息***********************************/

    /**
     * 获取包名
     *
     * @param clazz 获取类
     * @return 包名
     */
    public static String getPackage(Class<?> clazz) {
        Package pck = clazz.getPackage();
        if (null != pck) {
            return pck.getName();
        } else {
            return STR_EMPTY;
        }
    }

    /**
     * 获取继承的父类的全类名
     *
     * @param clazz 获取类
     * @return 继承父类
     */
    public static String getSuperClassName(Class<?> clazz) {
        Class<?> superClass = clazz.getSuperclass();
        if (null != superClass) {
            return superClass.getName();
        } else {
            return STR_EMPTY;
        }
    }

    /**
     * 获取继承的父类的全类名
     *
     * @param className 获取类命
     * @return 父类全名
     */
    public static String getSuperClassName(String className) throws ClassNotFoundException {
        return getSuperClassName(Class.forName(className));
    }

    /**
     * 获取全类名
     *
     * @param clazz 获取类
     * @return 全类名
     */
    public static String getClassName(Class<?> clazz) {
        return clazz.getName();
    }

    /**
     * 获取实现的接口名
     *
     * @param clazz 获取类
     * @return 类实现接口
     */
    public static List<String> getInterfaces(Class<?> clazz) {
        Class<?>[] interfaces = clazz.getInterfaces();
        List<String> list = new ArrayList<>();

        for (Class<?> i : interfaces) {
            // 接口名
            String interfaceName = i.getSimpleName();
            list.add(interfaceName);
        }

        return list;
    }

    /**
     * 获取实现的接口名
     *
     * @param className 获取类全类命
     * @return 实现接口集合
     * @throws ClassNotFoundException 类未找到异常
     */
    public static List<String> getInterfaces(String className) throws ClassNotFoundException {
        return getInterfaces(Class.forName(className));
    }

    /**
     * 获取所有属性
     *
     * @param clazz 获取类
     * @return 所有属性，包含私有属性集合
     */
    public static List<String> getFields(Class<?> clazz) {
        Field[] fields = clazz.getDeclaredFields();
        return getFromFieldArray(fields);
    }

    /**
     * 获取所有属性
     *
     * @param className 获取类全类名
     * @return 所有属性，包含私有属性集合
     * @throws ClassNotFoundException 类未找到异常
     */
    public static List<String> getFields(String className) throws ClassNotFoundException {
        return getFields(Class.forName(className));
    }

    /**
     * 获取所有公共的属性
     *
     * @param clazz 获取类
     * @return 所有公共属性集合
     */
    public static List<String> getPublicFields(Class<?> clazz) {
        Field[] fields = clazz.getFields();
        return getFromFieldArray(fields);
    }

    /**
     * 获取所有公共的属性
     *
     * @param className 获取类全类名
     * @return 所有公共属性集合
     * @throws ClassNotFoundException 类未找到异常
     */
    public static List<String> getPublicFields(String className) throws ClassNotFoundException {
        return getPublicFields(Class.forName(className));
    }

    /**
     * 获取所有构造方法
     *
     * @param clazz 获取类
     * @return 该类所有构造方法集合
     */
    public static List<String> getConstructors(Class<?> clazz) {
        Constructor<?>[] constructors = clazz.getDeclaredConstructors();
        List<String> list = new ArrayList<>();
        StringBuilder sb = null;

        for (Constructor<?> constructor : constructors) {
            sb = new StringBuilder();

            // 修饰符
            String modifier = Modifier.toString(constructor.getModifiers());
            sb.append(modifier).append(" ");

            // 方法名（类名）
            String constructorName = clazz.getSimpleName();
            sb.append(constructorName).append(" (");

            // 形参列表
            Class<?>[] parameterTypes = constructor.getParameterTypes();

            int len = parameterTypes.length;
            for (int i = 0; len > i; i++) {
                Class<?> parameterType = parameterTypes[i];
                String parameterTypeName = parameterType.getSimpleName();

                if (i < len - 1) {
                    sb.append(parameterTypeName).append(", ");
                } else {
                    sb.append(parameterTypeName);
                }
            }
            sb.append(") {}");

            list.add(sb.toString());
        }

        return list;
    }

    /**
     * 获取所有构造方法
     *
     * @param className 获取类全类名
     * @return 该类所有构造方法集合
     */
    public static List<String> getConstructors(String className) throws ClassNotFoundException {
        return getConstructors(Class.forName(className));
    }

    /**
     * 获取所有自身的方法
     *
     * @param clazz 获取类
     * @return 该类所有的方法，包含私有方法集合
     */
    public static List<String> getMethods(Class<?> clazz) {
        Method[] methods = clazz.getDeclaredMethods();
        return getFromMethodArray(methods);
    }

    /**
     * 获取所有自身的方法
     *
     * @param className 获取类全类名
     * @return 该类所有的方法，包含私有方法集合
     * @throws ClassNotFoundException 类未找到异常
     */
    public static List<String> getMethods(String className) throws ClassNotFoundException {
        return getMethods(Class.forName(className));
    }

    /**
     * 获取所有公共的方法
     *
     * @param clazz 获取类
     * @return 该类所有的公有方法
     */
    public static List<String> getPublicMethods(Class<?> clazz) {
        Method[] methods = clazz.getMethods();
        return getFromMethodArray(methods);
    }

    /**
     * 获取所有公共的方法
     *
     * @param className 获取类全类名
     * @return 该类所有的公有方法
     * @throws ClassNotFoundException 类未找到异常
     */
    public static List<String> getPublicMethods(String className) throws ClassNotFoundException {
        return getPublicMethods(Class.forName(className));
    }

    /**
     * 获取所有的注解名
     *
     * @param clazz 获取类
     * @return 获取类所有的注解
     */
    public static List<String> getAnnotations(Class<?> clazz) {
        Annotation[] annotations = clazz.getAnnotations();

        List<String> list = new ArrayList<>();
        for (Annotation annotation : annotations) {
            String annotationName = annotation.annotationType().getSimpleName();
            list.add(annotationName);
        }

        return list;
    }

    /**
     * 获取所有的注解名
     *
     * @param className 获取类全类名
     * @return 获取类所有的注解
     * @throws ClassNotFoundException 类未找到异常
     */
    public static List<String> getAnnotations(String className) throws ClassNotFoundException {
        return getAnnotations(Class.forName(className));
    }

    /**
     * 获取父类的泛型
     *
     * @param clazz 获取类
     * @return 父类泛型类
     */
    public static Class<?> getSuperClassGenericParameterizedType(Class<?> clazz) {
        Type genericSuperClass = clazz.getGenericSuperclass();
        Class<?> superClassGenericParameterizedType = null;

        // 判断父类是否有泛型
        if (genericSuperClass instanceof ParameterizedType) {
            // 向下转型，以便调用方法
            ParameterizedType pt = (ParameterizedType) genericSuperClass;
            // 只取第一个，因为一个类只能继承一个父类
            Type superClazz = pt.getActualTypeArguments()[0];
            // 转换为Class类型
            superClassGenericParameterizedType = (Class<?>) superClazz;
        }

        return superClassGenericParameterizedType;
    }

    /**
     * 获取父类的泛型
     *
     * @param className 获取类全类名
     * @return 父类泛型类
     * @throws ClassNotFoundException 类未找到异常
     */
    public static Class<?> getSuperClassGenericParameterizedType(String className) throws ClassNotFoundException {
        return getSuperClassGenericParameterizedType(Class.forName(className));
    }

    /**
     * 获取接口的所有泛型
     *
     * @param clazz 获取类
     * @return 接口的所有泛型
     */
    public static List<Class<?>> getInterfaceGenericParameterizedTypes(Class<?> clazz) {
        Type[] genericInterfaces = clazz.getGenericInterfaces();
        int len = genericInterfaces.length;

        List<Class<?>> list = new ArrayList<>();
        for (Type genericInterface : genericInterfaces) {
            // 判断接口是否有泛型
            if (genericInterface instanceof ParameterizedType) {
                ParameterizedType pt = (ParameterizedType) genericInterface;

                // 得到所有的泛型【Type类型的数组】
                Type[] interfaceTypes = pt.getActualTypeArguments();

                int length = interfaceTypes.length;

                for (Type interfaceType : interfaceTypes) {
                    // 获取对应的泛型【Type类型】
                    // 转换为Class类型
                    Class<?> interfaceClass = (Class<?>) interfaceType;
                    list.add(interfaceClass);
                }

            }

        }

        return list;
    }

    /**
     * 获取接口的所有泛型
     *
     * @param className 获取类全类名
     * @return 接口的所有泛型
     */
    public static List<Class<?>> getInterfaceGenericParameterizedTypes(String className) throws ClassNotFoundException {
        return getInterfaceGenericParameterizedTypes(Class.forName(className));
    }

    /**
     * 获取一个类的相关信息
     *
     * @param clazz 获取类
     * @return 类的字符描述信息
     */
    public static String getAllMsg(Class<?> clazz) {
        StringBuilder sb = new StringBuilder();
        sb.append("【包名】  ").append(getPackage(clazz)).append("\n");
        sb.append("【类名】  ").append(clazz.getSimpleName()).append("\n");
        sb.append("【父类全类名】").append(getSuperClassName(clazz)).append("\n");
        sb.append("【全类名】").append(getClassName(clazz)).append("\n");
        sb.append("【所有已实现的接口】").append(getInterfaces(clazz)).append("\n");
        sb.append("【属性】").append(getFields(clazz)).append("\n");
        sb.append("【构造方法】").append(getConstructors(clazz)).append("\n");
        sb.append("【方法】").append(getMethods(clazz)).append("\n");
        sb.append("【公共的属性】").append(getPublicFields(clazz)).append("\n");
        sb.append("【公共的方法】").append(getPublicMethods(clazz)).append("\n");
        return sb.toString();
    }

    /**
     * 获取一个类的相关信息
     *
     * @param className 获取类全类名
     * @return 类的字符描述信息
     */
    public static String getAllMsg(String className) throws ClassNotFoundException {
        return getAllMsg(Class.forName(className));
    }

    /**
     * 获取一个对象的属性信息
     *
     * @param obj 获取对象
     * @return 对象的类的属性信息
     */
    public static String getAllProp(Object obj) {
        return getAllProp(obj, false);
    }

    /**
     * 获取一个对象的属性信息
     *
     * @param obj 获取对象
     * @return 对象的类的属性信息
     */
    public static String getAllDetailProp(Object obj) {
        return getAllProp(obj, true);
    }

    /**
     * 根据传入的方法名字符串，获取对应的方法
     *
     * @param clazz          类
     * @param name           方法名称
     * @param parameterTypes 参数类型
     * @return 对应方法
     * @throws NoSuchMethodException 无方法异常
     * @throws SecurityException     安全异常
     */
    public static Method getMethod(Class<?> clazz, String name, Class<?>... parameterTypes)
            throws NoSuchMethodException, SecurityException {
        return clazz.getDeclaredMethod(name, parameterTypes);
    }

    /**
     * 根据传入的类的Class对象，以及构造方法的形参的Class对象，获取对应的构造方法对象
     *
     * @param clazz          获取类
     * @param parameterTypes 传入参数类型
     * @return 构造方法
     * @throws NoSuchMethodException 无方法异常
     * @throws SecurityException     安全异常
     */
    public static Constructor<?> getConstructor(Class<?> clazz, Class<?>... parameterTypes)
            throws NoSuchMethodException, SecurityException {
        return clazz.getDeclaredConstructor(parameterTypes);
    }

    /**
     * 根据传入的类的Class对象，以及构造方法的形参的Class对象，获取对应的构造方法对象
     *
     * @param className      获取类全类名
     * @param parameterTypes 传入参数类型
     * @return 构造方法
     * @throws NoSuchMethodException 无方法异常
     * @throws SecurityException     安全异常
     */
    public static Constructor<?> getConstructor(String className, Class<?>... parameterTypes)
            throws NoSuchMethodException, SecurityException, ClassNotFoundException {
        return Class.forName(className).getDeclaredConstructor(parameterTypes);
    }

    /****************************************************************************************/

    /************************************创建实例对象***********************************/

    /**
     * 根据传入的构造方法对象，以及构造参数获取对应的实例
     *
     * @param constructor 构造方法
     * @param initArgs    构造方法参数
     * @return 实例化对象
     * @throws InstantiationException    实例化异常
     * @throws IllegalAccessException    非法访问异常
     * @throws IllegalArgumentException  非法参数异常
     * @throws InvocationTargetException 调用异常
     */
    public static Object newInstance(Constructor<?> constructor, Object... initArgs)
            throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        constructor.setAccessible(true);
        return constructor.newInstance(initArgs);
    }

    /**
     * 根据Class类型，获取对应的实例（必须存在无参构造器）
     *
     * @param clazz 获取类
     * @return 实例化对象
     * @throws InstantiationException 实例化异常
     * @throws IllegalAccessException 非法访问异常
     */
    public static Object newInstance(Class<?> clazz) throws InstantiationException, IllegalAccessException {
        return clazz.newInstance();
    }

    /**
     * 根据Class类型，获取对应的实例（必须存在无参构造器）
     *
     * @param className 获取类全类名
     * @return 实例化对象
     * @throws InstantiationException 实例化异常
     * @throws IllegalAccessException 非法访问异常
     */
    public static Object newInstance(String className)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        return Class.forName(className).newInstance();
    }

    /**
     * 根据类以及构造形参类型，形参获取实例
     *
     * @param clazz     获取类
     * @param paraTypes 构造参数类型
     * @param paras     构造参数
     * @return 实例化对象
     * @throws InstantiationException    实例化异常
     * @throws IllegalAccessException    非法访问异常
     * @throws NoSuchMethodException     无方法异常
     * @throws InvocationTargetException 调用异常
     */
    public static Object newInstance(Class<?> clazz, Class<?>[] paraTypes, Object[] paras)
            throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Constructor<?> constructor = getConstructor(clazz, paraTypes);
        return newInstance(constructor, paras);
    }

    /**
     * 根据全类命以及构造形参类型，形参获取实例
     *
     * @param className 获取类全类名
     * @param paraTypes 构造参数类型
     * @param paras     构造参数
     * @return 实例化对象
     * @throws InstantiationException    实例化异常
     * @throws IllegalAccessException    非法访问异常
     * @throws NoSuchMethodException     无方法异常
     * @throws InvocationTargetException 调用异常
     */
    public static Object newInstance(String className, Class<?>[] paraTypes, Object[] paras)
            throws InstantiationException, IllegalAccessException, NoSuchMethodException,
            InvocationTargetException, ClassNotFoundException {
        Constructor<?> constructor = getConstructor(className, paraTypes);
        return newInstance(constructor, paras);
    }

    /**
     * 无参构造方法实例化对象
     *
     * @param className 全类名
     * @return 实例化对象
     * @throws InstantiationException    实例化异常
     * @throws IllegalAccessException    非法访问异常
     * @throws IllegalArgumentException  非法参数异常
     * @throws InvocationTargetException 调用异常
     * @throws ClassNotFoundException    找不到类
     * @throws NoSuchMethodException     无方法异常
     */
    public static Object newInstanceWithoutParaType(String className)
            throws InstantiationException, IllegalAccessException, IllegalArgumentException,
            InvocationTargetException, ClassNotFoundException, NoSuchMethodException {

        Class<?> c = Class.forName(className);

        Constructor<?> con = c.getConstructor(getConstructorParaClass(className));
        con.setAccessible(true);

        return con.newInstance();
    }

    /**
     * 有参构造方法实例化对象    注意：类结构复杂时谨慎使用
     *
     * @param className 全类名
     * @param conParas  构造参数
     * @return 实例化对象
     * @throws InstantiationException    实例化异常
     * @throws IllegalAccessException    非法访问异常
     * @throws IllegalArgumentException  非法参数异常
     * @throws InvocationTargetException 调用异常
     * @throws ClassNotFoundException    类未找到异常
     * @throws NoSuchMethodException     无方法异常
     */
    public static Object newInstanceWithoutParaType(String className, Object[] conParas)
            throws InstantiationException, IllegalAccessException, IllegalArgumentException,
            InvocationTargetException, ClassNotFoundException, NoSuchMethodException {

        Class<?> c = Class.forName(className);

        Constructor<?> con = c.getConstructor(getConstructorParaClass(className, conParas));
        con.setAccessible(true);

        return con.newInstance(conParas);
    }

    /****************************************************************************************/

    /************************************私有属性取值赋值***********************************/

    /**
     * 获取对象中属性值
     *
     * @param obj       传入对象
     * @param fieldName 属性名称
     * @return 属性值
     * @throws NoSuchFieldException   无属性异常
     * @throws IllegalAccessException 非法访问异常
     */
    public static Object getField(Object obj, String fieldName) throws NoSuchFieldException, IllegalAccessException {
        return getField(obj.getClass(), obj, fieldName);
    }

    /**
     * 获取对象中属性值（可用于获取继承父类的私有属性值）
     *
     * @param className 获取类
     * @param obj       传入对象
     * @param fieldName 属性名称
     * @return 属性值
     * @throws NoSuchFieldException   无属性异常
     * @throws IllegalAccessException 非法访问异常
     */
    public static Object getField(String className, Object obj, String fieldName) throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
        return getField(Class.forName(className), obj, fieldName);
    }

    /**
     * 获取对象中属性值（可用于获取继承父类的私有属性值）
     *
     * @param clazz     获取类
     * @param obj       传入对象
     * @param fieldName 属性名称
     * @return 属性值
     * @throws NoSuchFieldException   无属性异常
     * @throws IllegalAccessException 非法访问异常
     */
    public static Object getField(Class<?> clazz, Object obj, String fieldName) throws NoSuchFieldException, IllegalAccessException {
        Field field = clazz.getDeclaredField(fieldName);
        field.setAccessible(true);
        return field.get(obj);
    }

    /**
     * 根据传入的属性名字符串，修改对应的属性值
     *
     * @param obj       操作对象
     * @param fieldName 字段名称
     * @param value     值
     * @throws NoSuchFieldException     无属性异常
     * @throws SecurityException        安全异常
     * @throws IllegalArgumentException 非法参数异常
     * @throws IllegalAccessException   非法访问异常
     */
    public static void setField(Object obj, String fieldName, Object value)
            throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
        setField(obj.getClass(), fieldName, obj, value);
    }

    /**
     * 根据传入的属性名字符串，修改对应的属性值（可用于修改继承父类的私有属性值）
     *
     * @param className 类
     * @param fieldName 属性名称
     * @param obj       要修改的实例对象
     * @param value     修改后的属性值
     * @throws NoSuchFieldException     无属性异常
     * @throws SecurityException        安全异常
     * @throws IllegalArgumentException 非法参数异常
     * @throws IllegalAccessException   非法访问异常
     */
    public static void setField(String className, String fieldName, Object obj, Object value)
            throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, ClassNotFoundException {
        setField(Class.forName(className), fieldName, obj, value);
    }

    /**
     * 根据传入的属性名字符串，修改对应的属性值（可用于修改继承父类的私有属性值）
     *
     * @param clazz     类
     * @param fieldName 属性名称
     * @param obj       要修改的实例对象
     * @param value     修改后的属性值
     * @throws NoSuchFieldException     无属性异常
     * @throws SecurityException        安全异常
     * @throws IllegalArgumentException 非法参数异常
     * @throws IllegalAccessException   非法访问异常
     */
    public static void setField(Class<?> clazz, String fieldName, Object obj, Object value)
            throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
        Field field = clazz.getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value);
    }

    /****************************************************************************************/

    /************************************根据对象执行方法***********************************/

    /**
     * 根据传入的方法对象，调用对应的方法
     *
     * @param obj        获取对象
     * @param methodName 方法名称
     * @param parasType  方法参数类型
     * @param paras      方法参数
     * @return 调用方法返回对象
     * @throws NoSuchMethodException     无方法异常
     * @throws InvocationTargetException 调用异常
     * @throws IllegalAccessException    非法访问异常
     */
    public static Object invokeMethod(Object obj, String methodName, Class<?>[] parasType, Object[] paras)
            throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        return invokeMethod(obj.getClass(), obj, methodName, parasType, paras);
    }

    /**
     * 根据传入的方法对象，调用参数中类对应的方法（可用于调用继承父类的私有方法）
     *
     * @param className  获取类全类名
     * @param obj        获取对象
     * @param methodName 方法名称
     * @param parasType  方法参数类型
     * @param paras      方法参数
     * @return 方法返回结果
     * @throws NoSuchMethodException     无方法异常
     * @throws InvocationTargetException 调用目标异常
     * @throws IllegalAccessException    非法访问异常
     */
    public static Object invokeMethod(String className, Object obj, String methodName, Class<?>[] parasType, Object[] paras)
            throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException {
        return invokeMethod(Class.forName(className), obj, methodName, parasType, paras);
    }

    /**
     * 根据传入的方法对象，调用参数中类对应的方法（可用于调用继承父类的私有方法）
     *
     * @param clazz      获取类
     * @param obj        获取对象
     * @param methodName 方法名
     * @param parasType  方法参数类型
     * @param paras      方法参数
     * @return 方法返回结果
     * @throws NoSuchMethodException     无方法异常
     * @throws InvocationTargetException 方法调用对象异常
     * @throws IllegalAccessException    非法访问异常
     */
    public static Object invokeMethod(Class<?> clazz, Object obj, String methodName, Class<?>[] parasType, Object[] paras)
            throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Method m = getMethod(clazz, methodName, parasType);
        return invokeMethod(m, obj, paras);
    }

    /**
     * 根据传入的方法对象，调用对应的方法
     *
     * @param method 方法
     * @param obj    调用实例对象，若为静态方法，为null
     * @param args   方法参数
     * @return 方法返回结果
     * @throws IllegalAccessException    非法访问异常
     * @throws IllegalArgumentException  非法参数异常
     * @throws InvocationTargetException 调用目标异常
     */
    public static Object invokeMethod(Method method, Object obj, Object... args)
            throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        method.setAccessible(true);
        return method.invoke(obj, args);
    }

    /**
     * 方法无参，有操作对象反射方法调用
     *
     * @param obj        操作对象
     * @param methodName 方法名
     * @return 方法返回结果
     * @throws ClassNotFoundException    未找到类异常
     * @throws NoSuchMethodException     无方法异常
     * @throws IllegalAccessException    非法访问异常
     * @throws InvocationTargetException 调用对象异常
     */
    public static Object invokeWithoutParaType(Object obj, String methodName)
            throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        return invokeWithoutParaType(obj, methodName, new Object[]{});
    }

    /**
     * 方法无参，有操作对象反射方法调用（可用于调用继承父类的私有方法）
     *
     * @param className  获取类全类名
     * @param obj        获取对象
     * @param methodName 方法名
     * @return 方法返回结果
     * @throws ClassNotFoundException    未找到类异常
     * @throws NoSuchMethodException     无方法异常
     * @throws IllegalAccessException    非法访问异常
     * @throws InstantiationException    实例化异常
     * @throws InvocationTargetException 调用对象异常
     */
    public static Object invokeWithoutParaType(String className, Object obj, String methodName)
            throws ReflectiveOperationException {
        return invokeWithoutParaType(className, obj, methodName, new Object[]{});
    }

    /**
     * 方法无参，有操作对象反射方法调用（可用于调用继承父类的私有方法）
     *
     * @param clazz      获取类
     * @param obj        操作对象
     * @param methodName 方法名
     * @return 调用方法返回
     * @throws ClassNotFoundException    未找到类异常
     * @throws NoSuchMethodException     无方法异常
     * @throws IllegalAccessException    非法访问异常
     * @throws InvocationTargetException 调用对象异常
     */
    public static Object invokeWithoutParaType(Class<?> clazz, Object obj, String methodName)
            throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        return invokeWithoutParaType(clazz, obj, methodName, new Object[]{});
    }

    /**
     * 根据方法是否有参情况使用，有参方法调用    注意：类结构复杂时谨慎使用
     *
     * @param obj         获取对象
     * @param methodName  方法名
     * @param methodParas 方法参数
     * @return 方法返回结果
     * @throws ClassNotFoundException    未找到类异常
     * @throws NoSuchMethodException     无方法异常
     * @throws IllegalAccessException    非法访问异常
     * @throws InvocationTargetException 调用对象异常
     */
    public static Object invokeWithoutParaType(Object obj, String methodName, Object[] methodParas)
            throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        return invokeWithoutParaType(obj.getClass(), obj, methodName, methodParas);
    }

    /**
     * 根据方法是否有参情况使用，有参方法调用（可用于调用继承父类的私有方法）    注意：类结构复杂时谨慎使用
     *
     * @param className   获取类全类名
     * @param obj         操作对象
     * @param methodName  方法名
     * @param methodParas 方法参数
     * @return 方法返回结果
     * @throws ClassNotFoundException    未找到类异常
     * @throws NoSuchMethodException     无方法异常
     * @throws IllegalAccessException    非法访问异常
     * @throws InvocationTargetException 调用对象异常
     */
    public static Object invokeWithoutParaType(String className, Object obj, String methodName, Object[] methodParas)
            throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        Method m = Class.forName(className).getDeclaredMethod(methodName, getMethodParaClass(className, methodParas));
        m.setAccessible(true);
        return m.invoke(obj, methodParas);
    }

    /**
     * 根据方法是否有参情况使用，有参方法调用（可用于调用继承父类的私有方法）    注意：类结构复杂时谨慎使用
     *
     * @param clazz       获取类
     * @param obj         获取对象
     * @param methodName  方法名
     * @param methodParas 方法参数
     * @return 方法返回结果
     * @throws ClassNotFoundException    未找到类异常
     * @throws NoSuchMethodException     无方法异常
     * @throws IllegalAccessException    非法访问异常
     * @throws InvocationTargetException 调用对象异常
     */
    public static Object invokeWithoutParaType(Class<?> clazz, Object obj, String methodName, Object[] methodParas)
            throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        Method m = clazz.getDeclaredMethod(methodName, getMethodParaClass(clazz.getName(), methodParas));
        m.setAccessible(true);
        return m.invoke(obj, methodParas);
    }

    /****************************************************************************************/

    /***************************与对象无关，内部创建对象，执行方法*******************************/

    /**
     * 构造、方法无参反射调用
     *
     * @param className  获取类全类命
     * @param methodName 方法名
     * @return 方法返回结果
     * @throws ClassNotFoundException 未找到类异常
     * @throws NoSuchMethodException  无方法异常
     */
    public static Object runByReflection(String className, String methodName)
            throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException,
            InstantiationException, InvocationTargetException {
        return runByReflection(className, methodName, new Class<?>[]{}, new Object[]{});
    }

    /**
     * 根据构造以及方法是否有参情况使用    注意：类结构复杂时谨慎使用
     *
     * @param className   获取类全类命
     * @param conParas    构造参数
     * @param methodName  方法名
     * @param methodParas 方法参数
     * @return 方法返回结果
     * @throws ClassNotFoundException    未找到类异常
     * @throws NoSuchMethodException     无方法异常
     * @throws IllegalAccessException    非法访问异常
     * @throws InstantiationException    实例化异常
     * @throws InvocationTargetException 调用对象异常
     */
    public static Object runByReflectionX(String className, Object[] conParas, String methodName, Object[] methodParas)
            throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException,
            InstantiationException, InvocationTargetException {

        Class<?> c = Class.forName(className);


        Method m = c.getDeclaredMethod(methodName, getMethodParaClass(className, methodParas));
        m.setAccessible(true);

        return m.invoke(newInstanceWithoutParaType(className, conParas), methodParas);
    }

    /**
     * 根据构造以及方法是否有参情况使用
     *
     * @param className       获取类类命
     * @param conParaTypes    构造形参类型
     * @param conParas        构造参数
     * @param methodName      方法名
     * @param methodParaTypes 方法形参类型
     * @param methodParas     方法参数
     * @return 方法返回结果
     * @throws ClassNotFoundException    未找到类异常
     * @throws NoSuchMethodException     无方法异常
     * @throws IllegalAccessException    非法访问异常
     * @throws InstantiationException    实例化异常
     * @throws InvocationTargetException 调用对象异常
     */
    public static Object runByReflection(String className, Class<?>[] conParaTypes, Object[] conParas,
                                         String methodName, Class<?>[] methodParaTypes, Object[] methodParas)
            throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException,
            InstantiationException, InvocationTargetException {

        Class<?> c = Class.forName(className);


        Method m = c.getDeclaredMethod(methodName, methodParaTypes);
        m.setAccessible(true);

        return m.invoke(newInstance(className, conParaTypes, conParas), methodParas);
    }

    /**
     * 有无参构造的类的实例方法调用    注意：类结构复杂时谨慎使用
     *
     * @param className   获取类类命
     * @param methodName  方法名
     * @param methodParas 方法参数
     * @return 方法返回结果
     * @throws ClassNotFoundException    未找到类异常
     * @throws NoSuchMethodException     无方法异常
     * @throws IllegalAccessException    非法访问异常
     * @throws InstantiationException    实例化异常
     * @throws InvocationTargetException 调用对象异常
     */
    public static Object runByReflectionX(String className, String methodName, Object[] methodParas)
            throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException,
            InstantiationException, InvocationTargetException {
        return runByReflectionX(className, new Object[]{}, methodName, methodParas);
    }

    /**
     * 有无参构造的类的实例方法调用
     *
     * @param className       获取类类命
     * @param methodName      方法名
     * @param methodParaTypes 方法形参类型
     * @param methodParas     方法参数
     * @return 方法运行结果
     * @throws ClassNotFoundException    未找到类异常
     * @throws NoSuchMethodException     无方法异常
     * @throws IllegalAccessException    非法访问异常
     * @throws InstantiationException    实例化异常
     * @throws InvocationTargetException 调用对象异常
     */
    public static Object runByReflection(String className, String methodName, Class<?>[] methodParaTypes, Object[] methodParas)
            throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException,
            InstantiationException, InvocationTargetException {
        return runByReflection(className, new Class<?>[]{}, new Object[]{}, methodName, methodParaTypes, methodParas);
    }

    /**
     * 有参构造的类的实例，无参方法调用    注意：类结构复杂时谨慎使用
     *
     * @param className  获取类全类命
     * @param conParas   构造参数
     * @param methodName 方法名称
     * @return 方法运行结果
     * @throws ClassNotFoundException    未找到类异常
     * @throws NoSuchMethodException     无方法异常
     * @throws IllegalAccessException    非法访问异常
     * @throws InstantiationException    实例化异常
     * @throws InvocationTargetException 调用对象异常
     */
    public static Object runByReflectionX(String className, Object[] conParas, String methodName)
            throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException,
            InstantiationException, InvocationTargetException {
        return runByReflectionX(className, conParas, methodName, new Object[]{});
    }

    /**
     * 有参构造的类的实例，无参方法调用
     *
     * @param className    获取类全类命
     * @param conParaTypes 构造参数类型
     * @param conParas     构造参数
     * @param methodName   方法名称
     * @return 方法返回结果
     * @throws ClassNotFoundException    未找到类异常
     * @throws NoSuchMethodException     无方法异常
     * @throws IllegalAccessException    非法访问异常
     * @throws InstantiationException    实例化异常
     * @throws InvocationTargetException 调用对象异常
     */
    public static Object runByReflection(String className, Class<?>[] conParaTypes, Object[] conParas, String methodName)
            throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException,
            InstantiationException, InvocationTargetException {
        return runByReflection(className, conParaTypes, conParas, methodName, new Class<?>[]{}, new Object[]{});
    }

    /****************************************************************************************/

    /************************************单例模式执行方法**********************************/

    /**
     * 单例无参方法调用，默认获取实例方法为 getInstance
     *
     * @param className  获取类全类命
     * @param methodName 方法名
     * @return 方法返回结果
     * @throws ClassNotFoundException    未找到类异常
     * @throws NoSuchMethodException     无方法异常
     * @throws IllegalAccessException    非法访问异常
     * @throws InvocationTargetException 调用对象异常
     */
    public static Object runByReflection4Singleton(String className, String methodName)
            throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        return runByReflection4Singleton(className, methodName, new Class<?>[]{}, new Object[]{});
    }

    /**
     * 单例方法调用，默认获取实例方法为 getInstance    注意：类结构复杂时谨慎使用
     *
     * @param className   获取类全类命
     * @param methodName  方法名
     * @param methodParas 方法参数
     * @return 方法返回结果
     * @throws ClassNotFoundException    未找到类异常
     * @throws NoSuchMethodException     无方法异常
     * @throws IllegalAccessException    非法访问异常
     * @throws InvocationTargetException 方法调用异常
     */
    public static Object runByReflection4SingletonX(String className, String methodName, Object[] methodParas)
            throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        return runByReflection4SingletonX(className, FUNC_SINGLEINSTANCE, methodName, methodParas);
    }

    /**
     * 单例方法调用，默认获取实例方法为 getInstance
     *
     * @param className       获取类全类命
     * @param methodName      方法名
     * @param methodParaTypes 方法名
     * @param methodParas     方法参数
     * @return 方法返回结果
     * @throws ClassNotFoundException    未找到类异常
     * @throws NoSuchMethodException     无方法异常
     * @throws IllegalAccessException    非法访问异常
     * @throws InvocationTargetException 方法调用异常
     */
    public static Object runByReflection4Singleton(String className, String methodName, Class<?>[] methodParaTypes,
                                                   Object[] methodParas)
            throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        return runByReflection4Singleton(className, FUNC_SINGLEINSTANCE, methodName, methodParaTypes, methodParas);
    }

    /**
     * 单例方法调用    注意：类结构复杂时谨慎使用
     *
     * @param className             获取类全类命
     * @param getInstanceMethodName 单例方法名
     * @param methodName            方法名
     * @param methodParas           方法参数
     * @return 方法返回结果
     * @throws ClassNotFoundException    未找到类异常
     * @throws NoSuchMethodException     无方法异常
     * @throws IllegalAccessException    非法访问异常
     * @throws InvocationTargetException 调用对象异常
     */
    public static Object runByReflection4SingletonX(String className, String getInstanceMethodName,
                                                    String methodName, Object[] methodParas)
            throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {

        Class<?> c = Class.forName(className);

        Method m = c.getDeclaredMethod(methodName, getMethodParaClass(className, methodParas));
        m.setAccessible(true);

        // 获取实例方法，默认为 getInstance()
        Method getInsMet = c.getDeclaredMethod(getInstanceMethodName);

        // 获取单例
        Object instance = getInsMet.invoke(null);

        return m.invoke(instance, methodParas);
    }

    /**
     * 单例方法调用
     *
     * @param className             获取类全类命
     * @param getInstanceMethodName 单例方法名
     * @param methodName            方法名
     * @param methodParaTypes       方法形参类型
     * @param methodParas           方法参数
     * @return 方法返回结果
     * @throws ClassNotFoundException    未找到类异常
     * @throws NoSuchMethodException     无方法异常
     * @throws IllegalAccessException    非法访问异常
     * @throws InvocationTargetException 调用对象异常
     */
    public static Object runByReflection4Singleton(String className, String getInstanceMethodName,
                                                   String methodName, Class<?>[] methodParaTypes, Object[] methodParas)
            throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {

        Class<?> c = Class.forName(className);

        Method m = c.getDeclaredMethod(methodName, methodParaTypes);
        m.setAccessible(true);

        // 获取实例方法，默认为 getInstance()
        Method getInsMet = c.getDeclaredMethod(getInstanceMethodName);

        // 获取单例
        Object instance = getInsMet.invoke(null);

        return m.invoke(instance, methodParas);
    }

    /****************************************************************************************/

    /************************************静态方法执行**********************************/

    /**
     * 静态无参方法调用
     *
     * @param className  获取类全类名
     * @param methodName 方法名
     * @return 方法返回结果
     * @throws ClassNotFoundException    未找到类异常
     * @throws NoSuchMethodException     无方法异常
     * @throws IllegalAccessException    非法访问异常
     * @throws InvocationTargetException 调用对象异常
     */
    public static Object runStaticByReflection(String className, String methodName)
            throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException,
            InvocationTargetException {
        return runStaticByReflection(className, methodName, new Class<?>[]{}, new Object[]{});
    }

    /**
     * 静态方法调用    注意：类结构复杂时谨慎使用
     *
     * @param className   获取类全类名
     * @param methodName  方法名
     * @param methodParas 方法参数
     * @return 方法返回结果
     * @throws ClassNotFoundException    未找到类异常
     * @throws NoSuchMethodException     无方法异常
     * @throws IllegalAccessException    非法访问异常
     * @throws InvocationTargetException 调用对象异常
     */
    public static Object runStaticByReflectionX(String className, String methodName, Object[] methodParas)
            throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException,
            InvocationTargetException {

        Class<?> c = Class.forName(className);

        Method m = c.getDeclaredMethod(methodName, getMethodParaClass(className, methodParas));
        m.setAccessible(true);

        return m.invoke(null, methodParas);
    }

    /**
     * 静态方法调用
     *
     * @param className       获取类全类名
     * @param methodName      方法名
     * @param methodParaTypes 方法形参类型
     * @param methodParas     方法参数
     * @return 方法返回结果
     * @throws ClassNotFoundException    未找到类异常
     * @throws NoSuchMethodException     无方法异常
     * @throws IllegalAccessException    非法访问异常
     * @throws InvocationTargetException 调用对象异常
     */
    public static Object runStaticByReflection(String className, String methodName, Class<?>[] methodParaTypes, Object[] methodParas)
            throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException,
            InvocationTargetException {

        Class<?> c = Class.forName(className);

        Method m = c.getDeclaredMethod(methodName, methodParaTypes);
        m.setAccessible(true);

        return m.invoke(null, methodParas);
    }


    /****************************************************************************************/

    /*******************************私有方法，用于组织********************************/

    /**
     * 属性数组中取数
     *
     * @param fields 属性集合
     * @return 属性集合
     */
    private static List<String> getFromFieldArray(Field[] fields) {

        List<String> list = new ArrayList<>();
        StringBuilder sb;

        for (Field f : fields) {
            sb = new StringBuilder();

            // 修饰符
            String modifier = Modifier.toString(f.getModifiers());
            sb.append(modifier).append(" ");

            // 数据类型
            Class<?> type = f.getType();
            String typeName = type.getSimpleName();
            sb.append(typeName).append(" ");

            // 属性名
            String fieldName = f.getName();
            sb.append(fieldName);

            list.add(sb.toString());
        }

        return list;
    }

    /**
     * 方法数组中取数
     *
     * @param methods 方法
     * @return 方法集合
     */
    private static List<String> getFromMethodArray(Method[] methods) {
        List<String> list = new ArrayList<>();
        StringBuilder sb;
        for (Method method : methods) {
            sb = new StringBuilder();

            // 修饰符
            String modifier = Modifier.toString(method.getModifiers());
            sb.append(modifier).append(" ");

            // 返回值类型
            Class<?> returnClass = method.getReturnType();
            String returnType = returnClass.getSimpleName();
            sb.append(returnType).append(" ");

            // 方法名
            String methodName = method.getName();
            sb.append(methodName).append(" (");

            // 形参列表
            Class<?>[] parameterTypes = method.getParameterTypes();
            int len = parameterTypes.length;

            for (int i = 0; i < len; i++) {
                Class<?> parameterType = parameterTypes[i];

                // 形参类型
                String parameterTypeName = parameterType.getSimpleName();

                if (i < len - 1) {
                    sb.append(parameterTypeName).append(", ");
                } else {
                    sb.append(parameterTypeName);
                }
            }
            sb.append(") {}");

            list.add(sb.toString());
        }

        return list;
    }

    /**
     * 获取变量的类
     * 注意：基本数据类型 =》装箱后的类型
     *
     * @param paras 对象
     * @return 对象类型
     */
    private static Class<?>[] getParaClass(Object... paras) {

        if (paras == null) {
            throw new RuntimeException("内部转换错误，参数不允许为null");
        }

        int len = paras.length;

        Class<?>[] arr = new Class<?>[len];

        for (int i = 0; i < len; i++) {
            arr[i] = paras[i] == null ? Object.class : paras[i].getClass();
        }

        return arr;
    }

    /**
     * 判断是否匹配，先对应匹配，后基本数据类型匹配
     *
     * @param c   类
     * @param obj 对象
     * @return true为匹配
     */
    private static boolean isInstance(Class c, Object obj) {

        if (obj == null || c.isInstance(obj)) {
            return true;
        }

        Class<?> a = MAP_BASICTRAANSIT.get(obj.getClass());

        return a != null && c == a;
    }

    /**
     * 获取方法的参数类
     *
     * @param exes  可执行对象
     * @param paras 需要比对的参数
     * @return 方法参数类
     */
    private static Class<?>[] getFuncParaClass(Executable[] exes, Object... paras) {

        Class<?>[] res = null;

        // 获取基本参数
        Class<?>[] paraClass = getParaClass(paras);
        int paraClassLength = paraClass.length;

        label1:
        for (Executable exe : exes) {
            // 形参列表
            Class<?>[] paraTypes = exe.getParameterTypes();

            // 匹配到同样参数
            if (Arrays.equals(paraClass, paraTypes)) {
                return paraTypes;
            }

            int paraTypeLength = paraTypes.length;

            if (paraTypeLength != paraClassLength || res != null) {
                continue;
            }

            for (int i = 0; i < paraClassLength; i++) {
                if (!isInstance(paraTypes[i], paras[i])) {
                    continue label1;
                }
            }

            res = paraTypes;
        }

        if (res == null) {
            throw new RuntimeException("反射调用根据形参类型未匹配到形参类型可用的方法");
        }

        return res;
    }

    /**
     * 获取变量的方法参数类 =》构造函数
     * 获取方法：通过遍历反射类内的方法比对，获取最优匹配方法
     * 最优匹配原则，1、参数类型完全匹配；2、基本数据类型优先
     *
     * @param className 类命
     * @param paras     方法参数
     * @return 构造参数类
     */
    private static Class<?>[] getConstructorParaClass(String className, Object... paras)
            throws ClassNotFoundException {
        Class<?> c = Class.forName(className);
        Constructor<?>[] cons = c.getDeclaredConstructors();
        return getFuncParaClass(cons, paras);
    }

    /**
     * 获取变量的方法参数类 =》方法
     * 获取方法：通过遍历反射类内的方法比对，获取最优匹配方法
     * 最优匹配原则，1、参数类型完全匹配；2、基本数据类型优先
     *
     * @param className 类命
     * @param paras     方法参数
     * @return 方法参数类
     */
    private static Class<?>[] getMethodParaClass(String className, Object... paras)
            throws ClassNotFoundException {
        Class<?> c = Class.forName(className);
        Method[] methods = c.getDeclaredMethods();
        return getFuncParaClass(methods, paras);
    }

    /**
     * 获取对象所有属性
     *
     * @param obj  对象
     * @param flag 标识，若为 true，类型为详细信息，若为 false，类型为简易信息
     * @return 所有属性
     */
    private static String getAllProp(Object obj, boolean flag) {
        StringBuilder sb = new StringBuilder();

        Class<?> clazz = obj.getClass();
        sb.append("-----").append(clazz.getSimpleName()).append("-----\n");

        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);

            Object f;
            try {
                f = field.get(obj);
            } catch (IllegalAccessException e) {
                System.err.println(e.toString());
                f = e.getMessage();
            }

            sb.append(Modifier.toString(field.getModifiers())).append(" ").append(flag ? field.getClass().getName() :
                    field.getClass().getSimpleName())
                    .append(" ").append(field.getName()).append(" = ").append(f).append(" ;\n");
        }

        return sb.toString();
    }
    /****************************************************************************************/
}
